{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "FhGuhbZ6M5tl"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "AwOEIRJC6Une"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "KyPEtTqk6VdG"
      },
      "outputs": [],
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "EIdT9iu_Z4Rb"
      },
      "source": [
        "# Predict fuel efficiency: regression"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "bBIlTPscrIT9"
      },
      "source": [
        "\u003ctable class=\"tfo-notebook-buttons\" align=\"left\"\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/keras/basic_regression\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" /\u003eView on TensorFlow.org\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/en/tutorials/keras/basic_regression.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" /\u003eRun in Google Colab\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/en/tutorials/keras/basic_regression.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" /\u003eView source on GitHub\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "\u003c/table\u003e"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AHp3M9ZmrIxj"
      },
      "source": [
        "In a *regression* problem, we aim to predict the output of a continuous value, like a price or a probability. Contrast this with a *classification* problem, where we aim to predict a discrete label (for example, where a picture contains an apple or an orange). \n",
        "\n",
        "This notebook uses the classic [Auto MPG](https://archive.ics.uci.edu/ml/datasets/auto+mpg) Dataset and builds a model to predict the fuel efficiency of late-1970s and early 1980s automobiles. To do this, we'll provide the model with a description of many models from that time period. This description includes attributes like: cylinders,  displacement, horsepower, and weight.\n",
        "\n",
        "This example uses the `tf.keras` API, see [this guide](https://www.tensorflow.org/guide/keras) for details."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "moB4tpEHxKB3"
      },
      "outputs": [],
      "source": [
        "# Use seaborn for pairplot\n",
        "!pip install seaborn"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "1rRo8oNqZ-Rj"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import, division, print_function\n",
        "\n",
        "import pathlib\n",
        "\n",
        "import pandas as pd\n",
        "import seaborn as sns\n",
        "\n",
        "!pip install tf-nightly-2.0-preview\n",
        "import tensorflow as tf\n",
        "\n",
        "from tensorflow import keras\n",
        "from tensorflow.keras import layers\n",
        "\n",
        "print(tf.__version__)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "F_72b0LCNbjx"
      },
      "source": [
        "## The Auto MPG dataset\n",
        "\n",
        "The dataset is available from the [UCI Machine Learning Repository](https://archive.ics.uci.edu/).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "gFh9ne3FZ-On"
      },
      "source": [
        "### Get the data\n",
        "First download the dataset."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "p9kxxgzvzlyz"
      },
      "outputs": [],
      "source": [
        "dataset_path = keras.utils.get_file(\"auto-mpg.data\", \"https://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data\")\n",
        "dataset_path"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "nslsRLh7Zss4"
      },
      "source": [
        "Import it using pandas"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "CiX2FI4gZtTt"
      },
      "outputs": [],
      "source": [
        "column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',\n",
        "                'Acceleration', 'Model Year', 'Origin'] \n",
        "raw_dataset = pd.read_csv(dataset_path, names=column_names,\n",
        "                      na_values = \"?\", comment='\\t',\n",
        "                      sep=\" \", skipinitialspace=True)\n",
        "\n",
        "dataset = raw_dataset.copy()\n",
        "dataset.tail()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "3MWuJTKEDM-f"
      },
      "source": [
        "### Clean the data\n",
        "\n",
        "The dataset contains a few unknown values. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "JEJHhN65a2VV"
      },
      "outputs": [],
      "source": [
        "dataset.isna().sum()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "9UPN0KBHa_WI"
      },
      "source": [
        "To keep this initial tutorial simple drop those rows. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4ZUDosChC1UN"
      },
      "outputs": [],
      "source": [
        "dataset = dataset.dropna()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8XKitwaH4v8h"
      },
      "source": [
        "The `\"Origin\"` column is really categorical, not numeric. So convert that to a one-hot:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "gWNTD2QjBWFJ"
      },
      "outputs": [],
      "source": [
        "origin = dataset.pop('Origin')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "ulXz4J7PAUzk"
      },
      "outputs": [],
      "source": [
        "dataset['USA'] = (origin == 1)*1.0\n",
        "dataset['Europe'] = (origin == 2)*1.0\n",
        "dataset['Japan'] = (origin == 3)*1.0\n",
        "dataset.tail()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Cuym4yvk76vU"
      },
      "source": [
        "### Split the data into train and test\n",
        "\n",
        "Now split the data into a train and a test set.\n",
        "\n",
        "We will use the test set in the final evaluation of out model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "qn-IGhUE7_1H"
      },
      "outputs": [],
      "source": [
        "train_dataset = dataset.sample(frac=0.8,random_state=0)\n",
        "test_dataset = dataset.drop(train_dataset.index)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "J4ubs136WLNp"
      },
      "source": [
        "### Inspect the data\n",
        "\n",
        "Have a quick look at the joint distribution of a few pairs of columns from the training set."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "oRKO_x8gWKv-"
      },
      "outputs": [],
      "source": [
        "sns.pairplot(train_dataset[[\"MPG\", \"Cylinders\", \"Displacement\", \"Weight\"]], diag_kind=\"kde\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "gavKO_6DWRMP"
      },
      "source": [
        "Also look at the overall statistics:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "yi2FzC3T21jR"
      },
      "outputs": [],
      "source": [
        "train_stats = train_dataset.describe()\n",
        "train_stats.pop(\"MPG\")\n",
        "train_stats = train_stats.transpose()\n",
        "train_stats"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Db7Auq1yXUvh"
      },
      "source": [
        "### Split features from labels\n",
        "\n",
        "Not separate the target value, or \"label\" from the features.\n",
        "\n",
        "This label is the value that we will train our model to predict."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "t2sluJdCW7jN"
      },
      "outputs": [],
      "source": [
        "train_labels = train_dataset.pop('MPG')\n",
        "test_labels = test_dataset.pop('MPG')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mRklxK5s388r"
      },
      "source": [
        "### Normalize the data\n",
        "\n",
        "Look again at the `train_stats` block above and note how different the ranges of each feature are."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "-ywmerQ6dSox"
      },
      "source": [
        "It is good practice to normalize features that use different scales and ranges. Although the model *might* converge without feature normalization, it makes training more difficult, and it makes the resulting model dependent on the choice of units used in the input. \n",
        "\n",
        "Note: That we intentionally use the statistics from only the training set, these statistics will also be used for evaluation. This is so that the model doesn't have any information about the test set. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "JlC5ooJrgjQF"
      },
      "outputs": [],
      "source": [
        "def norm(x):\n",
        "  return (x - train_stats['mean']) / train_stats['std']\n",
        "normed_train_data = norm(train_dataset)\n",
        "normed_test_data = norm(test_dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "BuiClDk45eS4"
      },
      "source": [
        "This normalized data is what we will use to train the model.\n",
        "\n",
        "Caution: The statistics used to normalize the inputs here are as important as the model weights."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SmjdzxKzEu1-"
      },
      "source": [
        "## The model"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "6SWtkIjhrZwa"
      },
      "source": [
        "### Build the model\n",
        "\n",
        "Let's build our model. Here, we'll use a `Sequential` model with two densely connected hidden layers, and an output layer that returns a single, continuous value. The model building steps are wrapped in a function, `build_model`, since we'll create a second model, later on."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "c26juK7ZG8j-"
      },
      "outputs": [],
      "source": [
        "def build_model():\n",
        "  model = keras.Sequential([\n",
        "    layers.Dense(64, activation=tf.nn.relu, input_shape=[len(train_dataset.keys())]),\n",
        "    layers.Dense(64, activation=tf.nn.relu),\n",
        "    layers.Dense(1)\n",
        "  ])\n",
        "\n",
        "  optimizer = tf.keras.optimizers.RMSprop(0.001)\n",
        "\n",
        "  model.compile(loss='mse',\n",
        "                optimizer=optimizer,\n",
        "                metrics=['mae', 'mse'])\n",
        "  return model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "cGbPb-PHGbhs"
      },
      "outputs": [],
      "source": [
        "model = build_model()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Sj49Og4YGULr"
      },
      "source": [
        "### Inspect the model\n",
        "\n",
        "Use the `.summary` method to print a simple description of the model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "ReAD0n6MsFK-"
      },
      "outputs": [],
      "source": [
        "model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Vt6W50qGsJAL"
      },
      "source": [
        "\n",
        "Now try out the model. Take a batch of `10` exampes from the training data and call `model.predict` on it."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "-d-gBaVtGTSC"
      },
      "outputs": [],
      "source": [
        "example_batch = normed_train_data[:10]\n",
        "example_result = model.predict(example_batch)\n",
        "example_result"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "QlM8KrSOsaYo"
      },
      "source": [
        "It seems to be working, it produces a result of the expected shape and type. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "0-qWCsh6DlyH"
      },
      "source": [
        "### Train the model\n",
        "\n",
        "The model is trained for 1000 epochs, and record the training and validation accuracy in the `history` object."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "sD7qHCmNIOY0"
      },
      "outputs": [],
      "source": [
        "# Display training progress by printing a single dot for each completed epoch\n",
        "class PrintDot(keras.callbacks.Callback):\n",
        "  def on_epoch_end(self, epoch, logs):\n",
        "    if epoch % 100 == 0: print('')\n",
        "    print('.', end='')\n",
        "\n",
        "EPOCHS = 1000\n",
        "\n",
        "history = model.fit(\n",
        "  normed_train_data, train_labels,\n",
        "  epochs=EPOCHS, validation_split = 0.2, verbose=0,\n",
        "  callbacks=[PrintDot()])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "tQm3pc0FYPQB"
      },
      "source": [
        "Visualize the model's training progress using the stats stored in the `history` object."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4Xj91b-dymEy"
      },
      "outputs": [],
      "source": [
        "hist = pd.DataFrame(history.history)\n",
        "hist['epoch'] = history.epoch\n",
        "hist.tail()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "B6XriGbVPh2t"
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "def plot_history(history):\n",
        "  plt.figure()\n",
        "  plt.xlabel('Epoch')\n",
        "  plt.ylabel('Mean Abs Error [MPG]')\n",
        "  plt.plot(hist['epoch'], hist['mean_absolute_error'],\n",
        "           label='Train Error')\n",
        "  plt.plot(hist['epoch'], hist['val_mean_absolute_error'],\n",
        "           label = 'Val Error')\n",
        "  plt.legend()\n",
        "  plt.ylim([0,5])\n",
        "  \n",
        "  plt.figure()\n",
        "  plt.xlabel('Epoch')\n",
        "  plt.ylabel('Mean Square Error [$MPG^2$]')\n",
        "  plt.plot(hist['epoch'], hist['mean_squared_error'],\n",
        "           label='Train Error')\n",
        "  plt.plot(hist['epoch'], hist['val_mean_squared_error'],\n",
        "           label = 'Val Error')\n",
        "  plt.legend()\n",
        "  plt.ylim([0,20])\n",
        "\n",
        "plot_history(history)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AqsuANc11FYv"
      },
      "source": [
        "This graph shows little improvement, or even degradation in the validation error after a few hundred epochs. Let's update the `model.fit` method to automatically stop training when the validation score doesn't improve. We'll use a *callback* that tests a training condition for  every epoch. If a set amount of epochs elapses without showing improvement, then automatically stop the training.\n",
        "\n",
        "You can learn more about this callback [here](https://www.tensorflow.org/versions/master/api_docs/python/tf/keras/callbacks/EarlyStopping)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "fdMZuhUgzMZ4"
      },
      "outputs": [],
      "source": [
        "model = build_model()\n",
        "\n",
        "# The patience parameter is the amount of epochs to check for improvement\n",
        "early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=50)\n",
        "\n",
        "history = model.fit(normed_train_data, train_labels, epochs=EPOCHS,\n",
        "                    validation_split = 0.2, verbose=0, callbacks=[early_stop, PrintDot()])\n",
        "\n",
        "plot_history(history)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "3St8-DmrX8P4"
      },
      "source": [
        "The graph shows that on the validation set, the average error usually aeound +/- 2 MPG. Is this good? We'll leave that decision up to you.\n",
        "\n",
        "Let's see how did the model performs on the **test** set, which we did not use when training the model:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "jl_yNr5n1kms"
      },
      "outputs": [],
      "source": [
        "loss, mae, mse = model.evaluate(normed_test_data, test_labels, verbose=0)\n",
        "\n",
        "print(\"Testing set Mean Abs Error: {:5.2f} MPG\".format(mae))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ft603OzXuEZC"
      },
      "source": [
        "### Make predictions\n",
        "\n",
        "Finally, predict some housing prices using data in the testing set:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "Xe7RXH3N3CWU"
      },
      "outputs": [],
      "source": [
        "test_predictions = model.predict(normed_test_data).flatten()\n",
        "\n",
        "plt.scatter(test_labels, test_predictions)\n",
        "plt.xlabel('True Values [MPG]')\n",
        "plt.ylabel('Predictions [MPG]')\n",
        "plt.axis('equal')\n",
        "plt.axis('square')\n",
        "plt.xlim([0,plt.xlim()[1]])\n",
        "plt.ylim([0,plt.ylim()[1]])\n",
        "_ = plt.plot([-100, 100], [-100, 100])\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "f-OHX4DiXd8x"
      },
      "outputs": [],
      "source": [
        "error = test_predictions - test_labels\n",
        "plt.hist(error, bins = 25)\n",
        "plt.xlabel(\"Prediction Error [MPG]\")\n",
        "_ = plt.ylabel(\"Count\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vgGQuV-yqYZH"
      },
      "source": [
        "## Conclusion\n",
        "\n",
        "This notebook introduced a few techniques to handle a regression problem.\n",
        "\n",
        "* Mean Squared Error (MSE) is a common loss function used for regression problems (different than classification problems).\n",
        "* Similarly, evaluation metrics used for regression differ from classification. A common regression metric is Mean Absolute Error (MAE).\n",
        "* When input data features have values with different ranges, each feature should be scaled independently.\n",
        "* If there is not much training data, prefer a small network with few hidden layers to avoid overfitting.\n",
        "* Early stopping is a useful technique to prevent overfitting."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "basic-regression.ipynb",
      "private_outputs": true,
      "provenance": [],
      "toc_visible": true,
      "version": "0.3.2"
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
